#pragma once

#include <cstddef>
#include <utility>

/**
 * @brief 极简版 UniquePtr（独占所有权智能指针）。
 *
 * 设计目标：
 *   - 模仿 std::unique_ptr 的核心语义：独占所有权、移动语义、自定义删除器。
 *   - 便于教学理解，因此实现并未覆盖标准库全部特性（如数组偏特化、面向多态的默认删除器、make_unique 的完备实现等）。
 *
 * 注意事项：
 *   - 该实现仅用于单线程场景。
 *   - 删除器类型默认为函数指针 `void(*)(T*)`，指向一个简单的 `delete` 调用。
 */
template <typename T, typename Deleter = void(*)(T*)>
class UniquePtr {
public:
    using pointer      = T*;
    using element_type = T;
    using deleter_type = Deleter;

    /// 默认删除器：直接调用 delete 释放单个对象
    static void default_delete(T* ptr) noexcept {
        delete ptr;
    }

    /// 默认构造：不托管任何资源，删除器设为默认删除函数
    constexpr UniquePtr() noexcept
        : ptr_(nullptr)
        , deleter_(default_delete) {}

    /// nullptr 构造：与默认构造语义一致（委托构造）
    constexpr UniquePtr(std::nullptr_t) noexcept
        : UniquePtr() {}

    /**
     * @brief 裸指针构造：接管外部 new 得到的对象。
     *
     * @param ptr 需要托管的裸指针，必须来自 new。
     */
    explicit UniquePtr(pointer ptr) noexcept
        : ptr_(ptr)
        , deleter_(default_delete) {}

    /**
     * @brief 自定义删除器构造。
     *
     * @param ptr      需要托管的裸指针。
     * @param deleter  删除器对象（函数、函数指针、lambda 等）。
     */
    UniquePtr(pointer ptr, deleter_type deleter) noexcept
        : ptr_(ptr)
        , deleter_(std::move(deleter)) {}

    /// 禁用拷贝语义，确保“独占所有权”
    UniquePtr(const UniquePtr&)            = delete;
    UniquePtr& operator=(const UniquePtr&) = delete;

    /**
     * @brief 移动构造：接管 other 的资源并将其置空。
     *
     * @param other 被移动的 UniquePtr实例。
     */
    UniquePtr(UniquePtr&& other) noexcept
        : ptr_(other.ptr_)
        , deleter_(std::move(other.deleter_)) {
        other.ptr_ = nullptr;
    }

    /**
     * @brief 移动赋值：释放自身资源并接管 other 的资源。
     *
     * @param other 被移动的 UniquePtr 实例。
     * @return 当前对象引用，用于链式调用。
     */
    UniquePtr& operator=(UniquePtr&& other) noexcept {
        if (this != &other) {
            reset();                          // 释放自身已有资源
            ptr_     = other.ptr_;            // 接管指针
            deleter_ = std::move(other.deleter_);
            other.ptr_ = nullptr;             // 源对象置空
        }
        return *this;
    }

    /// 析构：自动释放（若持有资源）
    ~UniquePtr() {
        reset();
    }

    /**
     * @brief reset 重载：释放当前资源并接管新资源，删除器保持不变。
     *
     * @param ptr 新的裸指针（默认值为 nullptr，表示只释放不接管新资源）
     */
    void reset(pointer ptr = nullptr) noexcept {
        if (ptr_ != nullptr) {    // 仅当原本持有资源时才调用删除器
            deleter_(ptr_);
        }
        ptr_ = ptr;
    }

    /**
     * @brief reset 重载：同时更新指针与删除器。
     *
     * @param ptr     新的裸指针
     * @param deleter 新的删除器
     */
    void reset(pointer ptr, deleter_type deleter) noexcept {
        reset(ptr);                 // 先释放旧资源并接管新指针
        deleter_ = std::move(deleter);
    }

    /**
     * @brief release：放弃所有权，不删除对象。
     *
     * @return 原始裸指针；原 UniquePtr 不再托管该资源。
     */
    pointer release() noexcept {
        pointer raw = ptr_;
        ptr_ = nullptr;
        return raw;
    }

    /**
     * @brief 交换两个 UniquePtr 的资源与删除器。
     *
     * @param other 另一个 UniquePtr。
     */
    void swap(UniquePtr& other) noexcept {
        std::swap(ptr_, other.ptr_);
        std::swap(deleter_, other.deleter_);
    }

    /// 解引用操作符：返回被管理对象的引用
    element_type& operator*() const noexcept {
        return *ptr_;
    }

    /// 箭头操作符：访问被管理对象的成员
    pointer operator->() const noexcept {
        return ptr_;
    }

    /// 获取当前托管的裸指针
    pointer get() const noexcept {
        return ptr_;
    }

    /// bool 转换：是否持有资源
    explicit operator bool() const noexcept {
        return ptr_ != nullptr;
    }

    /// 获取删除器的引用（可修改）
    deleter_type& get_deleter() noexcept {
        return deleter_;
    }

    /// 获取删除器的常量引用（只读）
    const deleter_type& get_deleter() const noexcept {
        return deleter_;
    }

private:
    pointer      ptr_{nullptr};            ///< 当前托管的裸指针
    deleter_type deleter_{default_delete}; ///< 删除器对象
};

/**
 * @brief 非成员 swap：便于与 std::swap 一起工作。
 *
 * @param lhs 左操作数
 * @param rhs 右操作数
 */
template <typename T, typename Deleter>
void swap(UniquePtr<T, Deleter>& lhs, UniquePtr<T, Deleter>& rhs) noexcept {
    lhs.swap(rhs);
}

/**
 * @brief make_unique 的简化实现：返回 UniquePtr。
 *
 * @tparam T    对象类型
 * @tparam Args 构造参数类型（通过完美转发生成对象）
 * @param args  构造参数
 * @return UniquePtr<T> 接管新创建对象
 */
template <typename T, typename... Args>
UniquePtr<T> make_unique(Args&&... args) {
    return UniquePtr<T>(new T(std::forward<Args>(args)...));
}